<template>
  <div class="file-manager">
    <!-- title -->
    <PageTitle>
      {{ $t("menu.M_10402202") }}
    </PageTitle>
    <div>
      <div class="handle-box">
        <el-row class="flex items-center">
          <el-button-group style="margin-bottom: 10px; min-width: 25%">
            <el-button type="primary" size="small" @click="refreshPage()"
              ><svg-icon icon-class="Refresh"
            /></el-button>
            <el-button
              v-if="verifyPermission(['10402202.MANAGE'])"
              type="danger"
              :disabled="!permissionList.delBtn"
              size="small"
              @click="delVisible = true"
              ><svg-icon icon-class="Delete" />{{ $t("cmp.page_delete") }}
            </el-button>
            <el-popover
              v-if="verifyPermission(['10402202.MANAGE'])"
              v-model="popoverVisible"
              placement="bottom"
              width="380"
              style
              trigger="click"
            >
              <template #reference>
                <el-button
                  style="
                    border-left-color: rgba(255, 255, 255, 0.5);
                    border-top-left-radius: 0;
                    border-bottom-left-radius: 0;
                  "
                  type="primary"
                  :disabled="!permissionList.uploadBtn"
                  size="small"
                >
                  <svg-icon icon-class="Upload" /> {{ $t("cmp.page_upload") }}
                </el-button>
              </template>
              <el-upload
                ref="upload"
                class="upload-demo"
                :on-success="handleAvatarSuccess"
                :before-upload="beforeAvatarUpload"
                :on-exceed="handleExceed"
                :on-error="handleError"
                :on-remove="handleRemove"
                :file-list="fileList"
                :action="actionUrl"
                :headers="headers"
                :auto-upload="false"
                :limit="1"
                :multiple="false"
                drag
              >
                <div style="width: 360px">
                  <i class="el-icon-upload" />
                  <div class="el-upload__text">
                    {{ $t("cmp.msg_uploadOperating") }}
                    <em>{{ $t("cmp.msg_clickUpload") }}</em>
                  </div>
                </div>
              </el-upload>
              <div style="text-align: right; margin: 0">
                <el-button size="small" type="text" @click="cancelUpload">{{
                  $t("cmp.msg_cancel")
                }}</el-button>
                <el-button type="primary" size="small" @click="submitUpload">{{
                  $t("cmp.msg_confirm")
                }}</el-button>
              </div>
            </el-popover>

            <el-button
              type="primary"
              :disabled="!permissionList.downloadBtn"
              size="small"
              @click="downloadFile"
              ><svg-icon icon-class="Download" />{{ $t("cmp.page_download") }}</el-button
            >
            <el-button
              v-if="verifyPermission(['10402202.MANAGE'])"
              type="success"
              style="
                border-left-color: rgba(255, 255, 255, 0.5);
                border-right-color: rgba(255, 255, 255, 0.5);
                border-radius: 0;
              "
              :disabled="!permissionList.creDirBtn"
              size="small"
              @click="creDirVisible = true"
              ><svg-icon icon-class="FolderAdd" />
              {{ $t("cmp.page_createDir") }}
            </el-button>
          </el-button-group>
          <el-breadcrumb separator="/" style="padding-left: 10px">
            <el-breadcrumb-item v-for="item in breadcrumbs" :key="item.pathId">
              <a
                style="
                  max-width: 100px;
                  white-space: nowrap;
                  overflow: hidden;
                  text-overflow: ellipsis;
                "
                class="hover:text-element-blue cursor-pointer text-md inline-block"
                @click="() => handleBreadCrumbClick(item)"
                >{{ item.label }}</a
              >
            </el-breadcrumb-item>
          </el-breadcrumb>
        </el-row>

        <!--                <span style="margin-left: 10px;">no items selected</span>-->
        <el-row :gutter="5">
          <el-col :span="6">
            <div style="background: white; min-height: 65vh; margin: 0">
              <el-autocomplete
                v-model.trim="filterText"
                :fetch-suggestions="queryFileName"
                class="filemanager-filter-input"
                :placeholder="$t('cmp.page_filterKeyWord')"
                style="margin-bottom: 10px"
                :trigger-on-focus="false"
                clearable
                @select="handleSelectSuggestion"
              />
              <div style="height: 65vh">
                <el-scrollbar style="height: 100%" wrap-class="tree-wrapper">
                  <el-tree
                    ref="tree"
                    :props="defaultProps"
                    node-key="pathId"
                    :filter-node-method="filterNode"
                    highlight-current
                    :default-expanded-keys="expandedKeys"
                    :load="loadNode"
                    lazy
                    @node-click="handleNodeClick"
                  >
                    <template v-slot="{ node, data }">
                      <span class="custom-tree-node">
                        <el-button v-if="data.loadmore" type="text">Load More</el-button>
                        <span
                          v-else
                          :ref="'pathId-' + data.pathId"
                          v-ellipsis="250"
                          class="inline-block"
                          :title="node.label"
                        >
                          <svg-icon icon-class="Folder" />
                          {{ node.label }}
                        </span>
                      </span>
                    </template>
                  </el-tree>
                </el-scrollbar>
              </div>
            </div>
          </el-col>
          <el-col :span="18">
            <el-card
              shadow="never"
              :body-style="{ padding: '0px' }"
              :current-page="tablePage"
              :page-size="12"
              :total="totalTableData"
              @current-change="handleTablePageChange"
            >
              <el-table
                stripe
                ref="multipleTable"
                tooltip-effect="dark"
                :data="tablePageData"
                @selection-change="handleSelectionChange"
              >
                <el-table-column type="selection" width="55" />
                <el-table-column
                  fixed
                  prop="fileName"
                  :label="$t('cmp.page_fileName')"
                  show-overflow-tooltip
                >
                  <template v-slot="scope">
                    <svg-icon
                      icon-class="Folder"
                      v-if="scope.row.fileType == 'Directory'"
                    /><svg-icon icon-class="Document" v-else />
                    <span style="margin-left: 5px">{{ scope.row.fileName }}</span>
                  </template>
                </el-table-column>
                <el-table-column prop="fileType" :label="$t('cmp.msg_type')" />
                <el-table-column prop="fileSize" :label="$t('cmp.msg_size') + ' (byte)'">
                  <template v-slot="scope">
                    <span
                      v-if="scope.row.fileType !== 'Directory'"
                      style="margin-left: 5px"
                      >{{ autoGetDiskSize(scope.row.fileSize) }}</span
                    >
                  </template>
                </el-table-column>
                <el-table-column
                  prop="creTime"
                  :label="$t('cmp.page_createTime')"
                  width="180"
                >
                  <template v-slot:header="scope">
                    <el-input
                      v-model.trim="searchBoxKeyword"
                      size="small"
                      placeholder="Search"
                      clearable
                      @input="searchTable"
                    />
                  </template>
                  <template v-slot="{ row }">
                    <span>{{ dateTimeFilter(row.creTime) }}</span>
                  </template>
                </el-table-column>
              </el-table>
            </el-card>
          </el-col>
        </el-row>
      </div>
    </div>

    <!--创建文件夹提示框-->
    <el-dialog
      append-to-body
      v-model="creDirVisible"
      :title="$t('cmp.page_createDir')"
      width="550px"
      @close="closeDialog('creDirform')"
    >
      <el-form
        ref="creDirform"
        :rules="dirRules"
        :model="dirForm"
        label-width="auto"
        @submit.prevent.native
        label-position="top"
      >
        <el-form-item :label="$t('cmp.page_curPath') + ':'">
          <el-input
            :value="this.routePaths.join(' / ')"
            :placeholder="$t('cmp.msg_enterTemplateName')"
            autocomplete="off"
            readonly
          />
        </el-form-item>
        <el-form-item :label="$t('cmp.page_dirName') + ':'" prop="folderName">
          <el-input
            v-model="dirForm.folderName"
            :maxlength="64"
            :placeholder="$t('cmp.msg_enterTemplateName')"
            autocomplete="off"
            @change="() => (dirForm.folderName = dirForm.folderName.trim())"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button text @click="cancelCreDir('creDirform')">{{
            $t("cmp.msg_cancel")
          }}</el-button>
          <el-button
            type="primary"
            :loading="buttonLoading"
            @click="saveCreDir('creDirform')"
            >{{ $t("cmp.msg_confirm") }}</el-button
          >
        </span>
      </template>
    </el-dialog>

    <!-- 删除提示框 -->
    <el-dialog
      append-to-body
      v-model="delVisible"
      :title="$t('cmp.msg_tips')"
      width="460px"
    >
      <div class="del-dialog-cnt">{{ $t("cmp.msg_deleteTips") }}</div>
      <template #footer>
        <span class="dialog-footer">
          <el-button text @click="delVisible = false">{{
            $t("cmp.msg_cancel")
          }}</el-button>
          <el-button v-request="deleteRow" type="primary">{{
            $t("cmp.msg_confirm")
          }}</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script>
// import Base from '@/components/common/Base'
import { getToken } from "@/utils/auth";
import store from "@/store";
import { getDiskSize } from "@/utils";
import { verifyBtnPermission } from "@/utils";
import {
  querySubPathsByParent,
  findAllParentByPathId,
  querySubsByParentPath,
  createDir,
  deleteObj,
  queryPathListByCondition,
  queryDirectoryPath,
} from "@/api/parameter";
import { dateTimeFilter } from "@/filters";
import PageTitle from "@/components/PageTitle/index.vue";
let filteredData = [];

export default {
  name: "FileManager",
  components: {
    PageTitle,
  },
  // extends: Base,
  data() {
    return {
      clickPath: { pathId: 0, label: "filestorages" },
      permissionList: {
        delBtn: false,
        downloadBtn: false,
        creDirBtn: true,
        uploadBtn: true,
      },
      fullData: [],
      treeData: [],
      expandedKeys: [],
      routePaths: ["filestorages"],
      filterText: "",
      headers: {
        "WEB-TOKEN": getToken(),
        LANG: localStorage.getItem(store.state.user.keys.storage.lang) || "en-US",
      },
      popoverVisible: false,
      fileList: [],
      defaultProps: {
        children: "children",
        label: "label",
        pathId: "pathId",
        hasMore: "hasMore",
        isLeaf: "leaf",
      },
      multipleSelection: [],
      tableData: [],
      tablePageData: [], // 当前页的数据
      creDirVisible: false,
      dirForm: {
        pathId: 0,
        folderName: "",
      },
      dirRules: {
        folderName: [
          {
            required: true,
            message: this.$t("cmp.rule_input"),
            trigger: "blur",
          },
          {
            validator: (rule, value, callback) => {
              if (value) {
                if (/^\s+$/.test(value)) {
                  // 纯空格报错
                  callback(new Error(this.$t("flyparam.invalid_input")));
                }
              }
              callback();
            },
          },
        ],
      },
      delVisible: false,
      node_had: [], // 触发 tree 的 :load=loadNode 重复触发  动态更新tree
      resolve_had: [], // 触发 tree 的 :load=loadNode 重复触发  动态更新tree
      treePage: 1,
      tablePage: 1,
      totalTableData: 0,
      totalTreePages: 0,
      searchBoxKeyword: "",
      buttonLoading: false,
      promises: [],
      breadcrumbs: [],
    };
  },
  computed: {
    actionUrl: function () {
      return (
        import.meta.env.VITE_APP_BASE_API +
        "/online/management/fly-parameter/resource/paths/" +
        this.clickPath.pathId +
        "/attaches"
      );
    },
  },
  watch: {
    clickPath: function (val) {
      this.listRoutes();
    },
    multipleSelection: function (val) {
      // console.log(val)
      if (val.length > 0) {
        this.permissionList.downloadBtn = val.length == 1;
        val.forEach((item) => {
          if (item.fileType == "Directory") {
            this.permissionList.downloadBtn = false;
            return;
          }
        });
        this.permissionList.delBtn = true;
      } else {
        this.permissionList.downloadBtn = false;
        this.permissionList.delBtn = false;
      }
    },
  },
  created() {
    this.getData();
  },
  mounted() {
    const dom = this.$el.querySelector(".tree-wrapper");
  },
  methods: {
    dateTimeFilter,
    verifyPermission(val) {
      return verifyBtnPermission(val);
    },
    async getData() {
      this.handleNodeClick(this.clickPath);
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(this.clickPath.pathId);
        this.requestNewData(this.node_had, this.resolve_had);
      });
    },
    queryFileName(queryString, cb) {
      queryPathListByCondition(queryString).then((res) => {
        const result = res.map((item) => {
          let parentPaths, label;
          if (item.parentPath) {
            parentPaths = item.parentPath.split("\\");
            label = parentPaths.join("/") + "/" + item.folderName;
          } else {
            label = item.folderName;
          }

          return { value: label, label: item.folderName, pathId: item.pathId };
        });
        console.log(result);
        cb(result);
      });
    },
    // 搜索框输入后选中某一个选项
    handleSelectSuggestion(item) {
      // 滚动到选中的元素
      const el = this.$refs["pathId-" + item.pathId];
      this.filterText = "";
      if (el) {
        el.scrollIntoView({ behavior: "smooth" });
      }
      queryDirectoryPath(item.pathId).then((res) => {
        const { pathIds, labels } = res;
        this.ancestorsPathIds = pathIds.filter((id) => item.pathId !== id);
        this.parentPathId = pathIds[pathIds.length - 2];
        this.pathId = item.pathId;

        const node = this.$refs.tree.getNode(item.pathId);
        const parentNode = this.$refs.tree.getNode(this.parentPathId);
        // 搜索的节点还未被加载到树上，但节点的父节点在
        if (!node && parentNode) {
          if (parentNode.loaded) {
            this.loadmore(parentNode);
          } else {
            return this.handleNodeClick({
              pathId: parentNode.data.pathId,
              label: parentNode.data.label,
            });
          }
        }

        this.handleNodeClick({ pathId: item.pathId, label: item.label }, node);

        this.$refs.tree.setCurrentKey(item.pathId);
      });
    },
    expandNodes(node) {
      for (let i = 0; i < node.childNodes.length; i++) {
        node.childNodes[i].expanded = true;
        if (node.childNodes[i].childNodes.length > 0) {
          this.expandNodes(node.childNodes[i]);
        }
      }
    },
    autoGetDiskSize(num) {
      return getDiskSize(num);
    },
    remove(node, data) {
      const parent = node.parent;
      const children = parent.childNodes;
      const index = children.findIndex((d) => d.data.pathId === "loadmore");
      children.splice(index, 1);
    },
    loadNode(node, resolve) {
      if (node.data && node.data.loadmore) {
        // const parent = node.parent
        // const children = parent.childNodes
        // const index = children.findIndex(d => d.data.pathId === 'loadmore')
        // children.splice(index, 1)
        // parent.treeData.splice(index, 1)
        this.loadmore(node.parent);
        return;
      }
      if (node.level === 0) {
        this.node_had = node; // 这里是关键！在data里面定义一个变量，将node.level == 0的node存起来
        this.resolve_had = resolve; // 同上，把node.level == 0的resolve也存起来
        return resolve([{ pathId: 0, label: "filestorages" }]);
      } else if (node.level >= 1) {
        querySubPathsByParent({ pathId: node.data.pathId }).then((res) => {
          let _res = [];
          _res = res;

          node.fullData = _res;
          node.treeData = _res.slice(0, 100);
          node.resolve = resolve;
          node.treePage = 1;

          node.totalTreePages = Math.max(1, Math.ceil(node.fullData.length / 100));
          if (node.totalTreePages > 1) {
            node.treeData.push({
              loadmore: true,
              pathId: "loadmore",
              label: "Load More",
            });
            console.log(this.ancestorsPathIds);
            console.log(node.data.pathId);
            if (
              this.ancestorsPathIds &&
              this.ancestorsPathIds.includes(node.data.pathId)
            ) {
              const index = node.fullData.findIndex(
                (item) => item.pathId === this.pathId
              );
              const page = Math.floor(index / 100) + 1;
              this.loadmore(node, page);
              // node.treePage = page
              // node.treeData.push(...node.fullData.slice((node.treePage - 1) * 100, node.treePage * 100))
              // resolve(node.treeData)

              // this.$nextTick(() => {
              //   const el = this.$refs['pathId-' + this.pathId ]
              //   if (el) {
              //     el.scrollIntoView({ behavior: 'smooth' })
              //     this.$refs.tree.setCurrentKey(this.pathId)
              //   }
              // })

              return;
            }
          }
          resolve(node.treeData);
        });
      }
    },
    refreshPage() {
      this.treePage = 0;
      this.filterText = "";
      this.tablePage = 1;
      this.searchBoxKeyword = "";
      this.getData();
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    listRoutes() {
      this.routePaths = [];
      this.expandedKeys = [];
      findAllParentByPathId({ pathId: this.clickPath.pathId }).then((res) => {
        this.expandedKeys = [0].concat(res.pathIds);
        this.routePaths = ["filestorages"].concat(res.labels);
      });
    },
    requestNewData() {
      this.node_had.childNodes = []; // 把存起来的node的子节点清空，不然会界面会出现重复树！
      this.loadNode(this.node_had, this.resolve_had); // 再次执行懒加载的方法
    },
    handleNodeClick(data, node) {
      // 点击的节点是加载更多节点的按钮
      if (node && node.data && node.data.loadmore) {
        return;
      } else {
        this.clickPath = data;
        this.tableData = [];
        this.tablePage = 1;
        this.searchBoxKeyword = "";
        this.$_querySubsParentByPath();
        if (node) {
          this.breadcrumbs = this.addBread(data, node);
        }
      }
      // 重复渲染树
      // this.requestNewData(this.node_had, this.resolve_had)
    },
    addBread(data, node, arr = []) {
      console.log(data, node);
      arr.unshift({ pathId: data.pathId, label: data.label, level: node.level, node });
      if (node.parent.data) {
        this.addBread(node.parent.data, node.parent, arr);
      }
      return arr;
    },
    handleBreadCrumbClick(item) {
      this.handleNodeClick({ pathId: item.pathId, label: item.label }, item.node);
      this.$refs.tree.setCurrentKey(item.pathId);
    },
    $_querySubsParentByPath() {
      querySubsByParentPath(this.clickPath.pathId).then((res) => {
        res.pathList.forEach((item) => {
          const data = {
            id: item.pathId,
            fileName: item.folderName,
            fileSize: 0,
            creTime: item.creTime,
            fileType: "Directory",
          };
          this.tableData.push(data);
        });
        res.attachList.forEach((item) => {
          const data = {
            id: item.attachId,
            fileName: item.fileName,
            fileSize: item.fileSize,
            creTime: item.creTime,
            fileType: item.fileType,
          };
          this.tableData.push(data);
        });
        this.totalTableData = this.tableData.length;
        this.tablePageData = this.tableData.slice(
          (this.tablePage - 1) * 12,
          this.tablePage * 12
        );
      });
    },
    handleSelectionChange(val) {
      console.log(val);
      this.multipleSelection = val;
    },
    submitUpload() {
      this.$refs.upload.submit();
    },
    // 删除文件之前的钩子函数
    handleRemove(file, fileList) {},
    // 上传的文件个数超出设定时触发的函数
    handleExceed(files, fileList) {
      this.$message({
        type: "info",
        message: this.$t("cmp.msg_uploadLimit"),
        duration: 6000,
      });
    },
    beforeAvatarUpload(file) {
      if (file.size / 1024 / 1024 >= 100) {
        this.fileList = [];
        return this.$message.error(this.$t("common.file_size_limit", { limit: 100 }));
      }
    },
    handleAvatarSuccess(res, file) {
      this.fileList = [];
      this.popoverVisible = false;
      this.$message.success(this.$t("cmp.msg_uploadSuccess"));
      this.getData();
    },
    handleError(err) {
      if (err.message) {
        this.$message.error(JSON.parse(err.message));
      } else {
        this.$message.error(this.$t("common.message.network_error"));
      }
    },
    cancelUpload() {
      this.popoverVisible = false;
      this.fileList = [];
    },
    downloadFile() {
      window.open(
        import.meta.env.VITE_APP_BASE_API +
          "/online/management/fly-parameter/resource/paths/" +
          this.clickPath.pathId +
          "/attaches/" +
          this.multipleSelection[0].id +
          "?WEB-TOKEN=" +
          getToken(),
        "_self"
      );
    },
    cancelCreDir(formName) {
      this.$nextTick(() => {
        this.creDirVisible = false;
      });
    },
    saveCreDir(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.buttonLoading = true;
          this.dirForm.pathId = this.clickPath.pathId;
          createDir(this.dirForm)
            .then((res) => {
              this.buttonLoading = false;
              this.creDirVisible = false;
              this.$message.success(this.$t("cmp.msg_succeed"));
              this.getData();
            })
            .catch((err) => {
              this.$confirmError(err);
              this.buttonLoading = false;
            });
        } else {
          console.log("error create directory!!");
          return false;
        }
      });
    },
    closeDialog(formName) {
      this.$refs[formName].resetFields();
    },
    // 确定删除
    deleteRow() {
      return new Promise((resolve, reject) => {
        deleteObj({
          pathId: this.clickPath.pathId,
          list: this.multipleSelection,
        })
          .then((res) => {
            this.delVisible = false;
            this.$message.success(this.$t("cmp.msg_delSucceed"));
            this.getData();
            resolve(res);
          })
          .catch((err) => {
            reject(err);
          });
      });
    },
    loadmore(node, page) {
      const children = node.childNodes;
      const index = children.findIndex((d) => d.data.pathId === "loadmore");
      children.splice(index, 1);
      node.treeData.splice(index, 1);

      if (node.treePage >= node.totalTreePages) {
        return;
      }

      if (page) {
        node.treePage = page;
      } else {
        node.treePage++;
      }

      if (!page || page !== 1) {
        node.treeData.push(
          ...node.fullData.slice((node.treePage - 1) * 100, node.treePage * 100)
        );
      }

      node.treeData.push({
        loadmore: true,
        label: "Load More",
        pathId: "loadmore",
      });
      node.resolve(node.treeData);
    },
    handleTablePageChange(page) {
      this.tablePage = page;
      if (this.searchBoxKeyword) {
        this.tablePageData = filteredData.slice(
          (this.tablePage - 1) * 12,
          this.tablePage * 12
        );
      } else {
        this.tablePageData = this.tableData.slice(
          (this.tablePage - 1) * 12,
          this.tablePage * 12
        );
      }
    },
    searchTable() {
      this.tablePage = 1;
      if (!this.searchBoxKeyword) {
        this.tablePageData = this.tableData.slice(
          (this.tablePage - 1) * 12,
          this.tablePage * 12
        );
        this.totalTableData = this.tableData.length;
      } else {
        filteredData = this.tableData.filter(
          (_) => _.fileName.indexOf(this.searchBoxKeyword) > -1
        );
        this.tablePageData = filteredData.slice(
          (this.tablePage - 1) * 12,
          this.tablePage * 12
        );
        this.totalTableData = filteredData.length;
      }
    },
  },
};
</script>

<style></style>

<style scoped>
.handle-box {
  margin-bottom: 20px;
}

.handle-select {
  width: 120px;
}

.handle-input {
  width: 300px;
  display: inline-block;
}

.del-dialog-cnt {
  font-size: 16px;
  text-align: center;
}

.table {
  width: 100%;
  font-size: 14px;
}

.red {
  color: #ff0000;
}

.mr10 {
  margin-right: 10px;
}

.left {
  width: 380px;
  height: 100%;
  /*float: left;*/
  /*background: #fff;*/
  /*border: 1px solid #ddd;*/
  /*border-radius: 5px;*/
}

.right {
  /*float: left;*/
  width: calc(100% - 410px);
  overflow-x: auto;
  height: 100%;
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 5px;
}

/*上传组件样式*/
/deep/.el-upload--text {
  width: 360px;
  height: 180px;
}

/deep/ .filemanager-filter-input .el-input__inner {
  border-radius: 0;
  border-color: #edf2f9;
  border-left: 0;
  border-right: 0;
  border-top: 0;
}

.tooltipContent {
  padding: 2px;
  min-width: 250px;
  overflow: auto;
}

.tooltipContent > p {
  color: #333;
  font-size: 14px;
  height: 30px;
  line-height: 30px;
  margin: 3px;
}
</style>

<style scoped lang="scss">
.file-manager {
  &::v-deep {
    .filemanager-filter-input {
      .el-input__inner:focus {
        box-shadow: none;
      }
    }
    // .el-table table tr.el-table__row td {
    //   padding: 8px 0;
    // }

    .el-scrollbar__wrap {
      overflow-x: hidden;
    }

    .fty-card {
      border-radius: 0;
    }
  }
}
</style>
